162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * vgic init sequence tests
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020, Red Hat, Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#define _GNU_SOURCE
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <sys/syscall.h>
1062306a36Sopenharmony_ci#include <asm/kvm.h>
1162306a36Sopenharmony_ci#include <asm/kvm_para.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "test_util.h"
1462306a36Sopenharmony_ci#include "kvm_util.h"
1562306a36Sopenharmony_ci#include "processor.h"
1662306a36Sopenharmony_ci#include "vgic.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define NR_VCPUS		4
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define REG_OFFSET(vcpu, offset) (((uint64_t)vcpu << 32) | offset)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define GICR_TYPER 0x8
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2)
2562306a36Sopenharmony_ci#define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct vm_gic {
2862306a36Sopenharmony_ci	struct kvm_vm *vm;
2962306a36Sopenharmony_ci	int gic_fd;
3062306a36Sopenharmony_ci	uint32_t gic_dev_type;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic uint64_t max_phys_size;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Helpers to access a redistributor register and verify the ioctl() failed or
3762306a36Sopenharmony_ci * succeeded as expected, and provided the correct value on success.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset,
4062306a36Sopenharmony_ci				    int want, const char *msg)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	uint32_t ignored_val;
4362306a36Sopenharmony_ci	int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
4462306a36Sopenharmony_ci					REG_OFFSET(vcpu, offset), &ignored_val);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t want,
5062306a36Sopenharmony_ci			      const char *msg)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	uint32_t val;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
5562306a36Sopenharmony_ci			    REG_OFFSET(vcpu, offset), &val);
5662306a36Sopenharmony_ci	TEST_ASSERT(val == want, "%s; want '0x%x', got '0x%x'", msg, want, val);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* dummy guest code */
6062306a36Sopenharmony_cistatic void guest_code(void)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	GUEST_SYNC(0);
6362306a36Sopenharmony_ci	GUEST_SYNC(1);
6462306a36Sopenharmony_ci	GUEST_SYNC(2);
6562306a36Sopenharmony_ci	GUEST_DONE();
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* we don't want to assert on run execution, hence that helper */
6962306a36Sopenharmony_cistatic int run_vcpu(struct kvm_vcpu *vcpu)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	return __vcpu_run(vcpu) ? -errno : 0;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type,
7562306a36Sopenharmony_ci					      uint32_t nr_vcpus,
7662306a36Sopenharmony_ci					      struct kvm_vcpu *vcpus[])
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct vm_gic v;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	v.gic_dev_type = gic_dev_type;
8162306a36Sopenharmony_ci	v.vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
8262306a36Sopenharmony_ci	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return v;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void vm_gic_destroy(struct vm_gic *v)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	close(v->gic_fd);
9062306a36Sopenharmony_ci	kvm_vm_free(v->vm);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistruct vgic_region_attr {
9462306a36Sopenharmony_ci	uint64_t attr;
9562306a36Sopenharmony_ci	uint64_t size;
9662306a36Sopenharmony_ci	uint64_t alignment;
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistruct vgic_region_attr gic_v3_dist_region = {
10062306a36Sopenharmony_ci	.attr = KVM_VGIC_V3_ADDR_TYPE_DIST,
10162306a36Sopenharmony_ci	.size = 0x10000,
10262306a36Sopenharmony_ci	.alignment = 0x10000,
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistruct vgic_region_attr gic_v3_redist_region = {
10662306a36Sopenharmony_ci	.attr = KVM_VGIC_V3_ADDR_TYPE_REDIST,
10762306a36Sopenharmony_ci	.size = NR_VCPUS * 0x20000,
10862306a36Sopenharmony_ci	.alignment = 0x10000,
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct vgic_region_attr gic_v2_dist_region = {
11262306a36Sopenharmony_ci	.attr = KVM_VGIC_V2_ADDR_TYPE_DIST,
11362306a36Sopenharmony_ci	.size = 0x1000,
11462306a36Sopenharmony_ci	.alignment = 0x1000,
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistruct vgic_region_attr gic_v2_cpu_region = {
11862306a36Sopenharmony_ci	.attr = KVM_VGIC_V2_ADDR_TYPE_CPU,
11962306a36Sopenharmony_ci	.size = 0x2000,
12062306a36Sopenharmony_ci	.alignment = 0x1000,
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/**
12462306a36Sopenharmony_ci * Helper routine that performs KVM device tests in general. Eventually the
12562306a36Sopenharmony_ci * ARM_VGIC (GICv2 or GICv3) device gets created with an overlapping
12662306a36Sopenharmony_ci * DIST/REDIST (or DIST/CPUIF for GICv2). Assumption is 4 vcpus are going to be
12762306a36Sopenharmony_ci * used hence the overlap. In the case of GICv3, A RDIST region is set at @0x0
12862306a36Sopenharmony_ci * and a DIST region is set @0x70000. The GICv2 case sets a CPUIF @0x0 and a
12962306a36Sopenharmony_ci * DIST region @0x1000.
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistatic void subtest_dist_rdist(struct vm_gic *v)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	int ret;
13462306a36Sopenharmony_ci	uint64_t addr;
13562306a36Sopenharmony_ci	struct vgic_region_attr rdist; /* CPU interface in GICv2*/
13662306a36Sopenharmony_ci	struct vgic_region_attr dist;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	rdist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_redist_region
13962306a36Sopenharmony_ci						: gic_v2_cpu_region;
14062306a36Sopenharmony_ci	dist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_dist_region
14162306a36Sopenharmony_ci						: gic_v2_dist_region;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* Check existing group/attributes */
14462306a36Sopenharmony_ci	kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, dist.attr);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, rdist.attr);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* check non existing attribute */
14962306a36Sopenharmony_ci	ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, -1);
15062306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == ENXIO, "attribute not supported");
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* misaligned DIST and REDIST address settings */
15362306a36Sopenharmony_ci	addr = dist.alignment / 0x10;
15462306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
15562306a36Sopenharmony_ci				    dist.attr, &addr);
15662306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "GIC dist base not aligned");
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	addr = rdist.alignment / 0x10;
15962306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
16062306a36Sopenharmony_ci				    rdist.attr, &addr);
16162306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "GIC redist/cpu base not aligned");
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* out of range address */
16462306a36Sopenharmony_ci	addr = max_phys_size;
16562306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
16662306a36Sopenharmony_ci				    dist.attr, &addr);
16762306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == E2BIG, "dist address beyond IPA limit");
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
17062306a36Sopenharmony_ci				    rdist.attr, &addr);
17162306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == E2BIG, "redist address beyond IPA limit");
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* Space for half a rdist (a rdist is: 2 * rdist.alignment). */
17462306a36Sopenharmony_ci	addr = max_phys_size - dist.alignment;
17562306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
17662306a36Sopenharmony_ci				    rdist.attr, &addr);
17762306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == E2BIG,
17862306a36Sopenharmony_ci			"half of the redist is beyond IPA limit");
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* set REDIST base address @0x0*/
18162306a36Sopenharmony_ci	addr = 0x00000;
18262306a36Sopenharmony_ci	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
18362306a36Sopenharmony_ci			    rdist.attr, &addr);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Attempt to create a second legacy redistributor region */
18662306a36Sopenharmony_ci	addr = 0xE0000;
18762306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
18862306a36Sopenharmony_ci				    rdist.attr, &addr);
18962306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EEXIST, "GIC redist base set again");
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
19262306a36Sopenharmony_ci				     KVM_VGIC_V3_ADDR_TYPE_REDIST);
19362306a36Sopenharmony_ci	if (!ret) {
19462306a36Sopenharmony_ci		/* Attempt to mix legacy and new redistributor regions */
19562306a36Sopenharmony_ci		addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 0, 0);
19662306a36Sopenharmony_ci		ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
19762306a36Sopenharmony_ci					    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
19862306a36Sopenharmony_ci		TEST_ASSERT(ret && errno == EINVAL,
19962306a36Sopenharmony_ci			    "attempt to mix GICv3 REDIST and REDIST_REGION");
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/*
20362306a36Sopenharmony_ci	 * Set overlapping DIST / REDIST, cannot be detected here. Will be detected
20462306a36Sopenharmony_ci	 * on first vcpu run instead.
20562306a36Sopenharmony_ci	 */
20662306a36Sopenharmony_ci	addr = rdist.size - rdist.alignment;
20762306a36Sopenharmony_ci	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
20862306a36Sopenharmony_ci			    dist.attr, &addr);
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/* Test the new REDIST region API */
21262306a36Sopenharmony_cistatic void subtest_v3_redist_regions(struct vm_gic *v)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	uint64_t addr, expected_addr;
21562306a36Sopenharmony_ci	int ret;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
21862306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST);
21962306a36Sopenharmony_ci	TEST_ASSERT(!ret, "Multiple redist regions advertised");
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 2, 0);
22262306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
22362306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
22462306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with flags != 0");
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(0, 0x100000, 0, 0);
22762306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
22862306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
22962306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with count== 0");
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
23262306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
23362306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
23462306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL,
23562306a36Sopenharmony_ci		    "attempt to register the first rdist region with index != 0");
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x201000, 0, 1);
23862306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
23962306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
24062306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "rdist region with misaligned address");
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
24362306a36Sopenharmony_ci	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
24462306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
24762306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
24862306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
24962306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "register an rdist region with already used index");
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(1, 0x210000, 0, 2);
25262306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
25362306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
25462306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL,
25562306a36Sopenharmony_ci		    "register an rdist region overlapping with another one");
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 2);
25862306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
25962306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
26062306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "register redist region with index not +1");
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
26362306a36Sopenharmony_ci	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
26462306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(1, max_phys_size, 0, 2);
26762306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
26862306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
26962306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == E2BIG,
27062306a36Sopenharmony_ci		    "register redist region with base address beyond IPA range");
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* The last redist is above the pa range. */
27362306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, max_phys_size - 0x30000, 0, 2);
27462306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
27562306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
27662306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == E2BIG,
27762306a36Sopenharmony_ci		    "register redist region with top address beyond IPA range");
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	addr = 0x260000;
28062306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
28162306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
28262306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL,
28362306a36Sopenharmony_ci		    "Mix KVM_VGIC_V3_ADDR_TYPE_REDIST and REDIST_REGION");
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/*
28662306a36Sopenharmony_ci	 * Now there are 2 redist regions:
28762306a36Sopenharmony_ci	 * region 0 @ 0x200000 2 redists
28862306a36Sopenharmony_ci	 * region 1 @ 0x240000 1 redist
28962306a36Sopenharmony_ci	 * Attempt to read their characteristics
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 0);
29362306a36Sopenharmony_ci	expected_addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
29462306a36Sopenharmony_ci	ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
29562306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
29662306a36Sopenharmony_ci	TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #0");
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 1);
29962306a36Sopenharmony_ci	expected_addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
30062306a36Sopenharmony_ci	ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
30162306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
30262306a36Sopenharmony_ci	TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #1");
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 2);
30562306a36Sopenharmony_ci	ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
30662306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
30762306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == ENOENT, "read characteristics of non existing region");
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	addr = 0x260000;
31062306a36Sopenharmony_ci	kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
31162306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(1, 0x260000, 0, 2);
31462306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
31562306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
31662306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "register redist region colliding with dist");
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/*
32062306a36Sopenharmony_ci * VGIC KVM device is created and initialized before the secondary CPUs
32162306a36Sopenharmony_ci * get created
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_cistatic void test_vgic_then_vcpus(uint32_t gic_dev_type)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct kvm_vcpu *vcpus[NR_VCPUS];
32662306a36Sopenharmony_ci	struct vm_gic v;
32762306a36Sopenharmony_ci	int ret, i;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	v = vm_gic_create_with_vcpus(gic_dev_type, 1, vcpus);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	subtest_dist_rdist(&v);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Add the rest of the VCPUs */
33462306a36Sopenharmony_ci	for (i = 1; i < NR_VCPUS; ++i)
33562306a36Sopenharmony_ci		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	ret = run_vcpu(vcpus[3]);
33862306a36Sopenharmony_ci	TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	vm_gic_destroy(&v);
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci/* All the VCPUs are created before the VGIC KVM device gets initialized */
34462306a36Sopenharmony_cistatic void test_vcpus_then_vgic(uint32_t gic_dev_type)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct kvm_vcpu *vcpus[NR_VCPUS];
34762306a36Sopenharmony_ci	struct vm_gic v;
34862306a36Sopenharmony_ci	int ret;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, vcpus);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	subtest_dist_rdist(&v);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	ret = run_vcpu(vcpus[3]);
35562306a36Sopenharmony_ci	TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	vm_gic_destroy(&v);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic void test_v3_new_redist_regions(void)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct kvm_vcpu *vcpus[NR_VCPUS];
36362306a36Sopenharmony_ci	void *dummy = NULL;
36462306a36Sopenharmony_ci	struct vm_gic v;
36562306a36Sopenharmony_ci	uint64_t addr;
36662306a36Sopenharmony_ci	int ret;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
36962306a36Sopenharmony_ci	subtest_v3_redist_regions(&v);
37062306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
37162306a36Sopenharmony_ci			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	ret = run_vcpu(vcpus[3]);
37462306a36Sopenharmony_ci	TEST_ASSERT(ret == -ENXIO, "running without sufficient number of rdists");
37562306a36Sopenharmony_ci	vm_gic_destroy(&v);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* step2 */
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
38062306a36Sopenharmony_ci	subtest_v3_redist_regions(&v);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
38362306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
38462306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	ret = run_vcpu(vcpus[3]);
38762306a36Sopenharmony_ci	TEST_ASSERT(ret == -EBUSY, "running without vgic explicit init");
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	vm_gic_destroy(&v);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* step 3 */
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
39462306a36Sopenharmony_ci	subtest_v3_redist_regions(&v);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
39762306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy);
39862306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EFAULT,
39962306a36Sopenharmony_ci		    "register a third region allowing to cover the 4 vcpus");
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
40262306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
40362306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
40662306a36Sopenharmony_ci			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	ret = run_vcpu(vcpus[3]);
40962306a36Sopenharmony_ci	TEST_ASSERT(!ret, "vcpu run");
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	vm_gic_destroy(&v);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic void test_v3_typer_accesses(void)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct vm_gic v;
41762306a36Sopenharmony_ci	uint64_t addr;
41862306a36Sopenharmony_ci	int ret, i;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	v.vm = vm_create(NR_VCPUS);
42162306a36Sopenharmony_ci	(void)vm_vcpu_add(v.vm, 0, guest_code);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	(void)vm_vcpu_add(v.vm, 3, guest_code);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL,
42862306a36Sopenharmony_ci				"attempting to read GICR_TYPER of non created vcpu");
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	(void)vm_vcpu_add(v.vm, 1, guest_code);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY,
43362306a36Sopenharmony_ci				"read GICR_TYPER before GIC initialized");
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	(void)vm_vcpu_add(v.vm, 2, guest_code);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
43862306a36Sopenharmony_ci			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	for (i = 0; i < NR_VCPUS ; i++) {
44162306a36Sopenharmony_ci		v3_redist_reg_get(v.gic_fd, i, GICR_TYPER, i * 0x100,
44262306a36Sopenharmony_ci				  "read GICR_TYPER before rdist region setting");
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
44662306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
44762306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* The 2 first rdists should be put there (vcpu 0 and 3) */
45062306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x0, "read typer of rdist #0");
45162306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #1");
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(10, 0x100000, 0, 1);
45462306a36Sopenharmony_ci	ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
45562306a36Sopenharmony_ci				    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
45662306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL, "collision with previous rdist region");
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100,
45962306a36Sopenharmony_ci			  "no redist region attached to vcpu #1 yet, last cannot be returned");
46062306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200,
46162306a36Sopenharmony_ci			  "no redist region attached to vcpu #2, last cannot be returned");
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(10, 0x20000, 0, 1);
46462306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
46562306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
46862306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210,
46962306a36Sopenharmony_ci			  "read typer of rdist #1, last properly returned");
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	vm_gic_destroy(&v);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus,
47562306a36Sopenharmony_ci						   uint32_t vcpuids[])
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct vm_gic v;
47862306a36Sopenharmony_ci	int i;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	v.vm = vm_create(nr_vcpus);
48162306a36Sopenharmony_ci	for (i = 0; i < nr_vcpus; i++)
48262306a36Sopenharmony_ci		vm_vcpu_add(v.vm, vcpuids[i], guest_code);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return v;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/**
49062306a36Sopenharmony_ci * Test GICR_TYPER last bit with new redist regions
49162306a36Sopenharmony_ci * rdist regions #1 and #2 are contiguous
49262306a36Sopenharmony_ci * rdist region #0 @0x100000 2 rdist capacity
49362306a36Sopenharmony_ci *     rdists: 0, 3 (Last)
49462306a36Sopenharmony_ci * rdist region #1 @0x240000 2 rdist capacity
49562306a36Sopenharmony_ci *     rdists:  5, 4 (Last)
49662306a36Sopenharmony_ci * rdist region #2 @0x200000 2 rdist capacity
49762306a36Sopenharmony_ci *     rdists: 1, 2
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_cistatic void test_v3_last_bit_redist_regions(void)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
50262306a36Sopenharmony_ci	struct vm_gic v;
50362306a36Sopenharmony_ci	uint64_t addr;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
50862306a36Sopenharmony_ci			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x100000, 0, 0);
51162306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
51262306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x240000, 0, 1);
51562306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
51662306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 2);
51962306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
52062306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
52362306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
52462306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200, "read typer of rdist #2");
52562306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #3");
52662306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #5");
52762306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, 0x410, "read typer of rdist #4");
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	vm_gic_destroy(&v);
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci/* Test last bit with legacy region */
53362306a36Sopenharmony_cistatic void test_v3_last_bit_single_rdist(void)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
53662306a36Sopenharmony_ci	struct vm_gic v;
53762306a36Sopenharmony_ci	uint64_t addr;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
54262306a36Sopenharmony_ci			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	addr = 0x10000;
54562306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
54662306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
54962306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x300, "read typer of rdist #1");
55062306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #2");
55162306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #3");
55262306a36Sopenharmony_ci	v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210, "read typer of rdist #3");
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	vm_gic_destroy(&v);
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/* Uses the legacy REDIST region API. */
55862306a36Sopenharmony_cistatic void test_v3_redist_ipa_range_check_at_vcpu_run(void)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct kvm_vcpu *vcpus[NR_VCPUS];
56162306a36Sopenharmony_ci	struct vm_gic v;
56262306a36Sopenharmony_ci	int ret, i;
56362306a36Sopenharmony_ci	uint64_t addr;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/* Set space for 3 redists, we have 1 vcpu, so this succeeds. */
56862306a36Sopenharmony_ci	addr = max_phys_size - (3 * 2 * 0x10000);
56962306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
57062306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	addr = 0x00000;
57362306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
57462306a36Sopenharmony_ci			    KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* Add the rest of the VCPUs */
57762306a36Sopenharmony_ci	for (i = 1; i < NR_VCPUS; ++i)
57862306a36Sopenharmony_ci		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
58162306a36Sopenharmony_ci			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/* Attempt to run a vcpu without enough redist space. */
58462306a36Sopenharmony_ci	ret = run_vcpu(vcpus[2]);
58562306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL,
58662306a36Sopenharmony_ci		"redist base+size above PA range detected on 1st vcpu run");
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	vm_gic_destroy(&v);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic void test_v3_its_region(void)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct kvm_vcpu *vcpus[NR_VCPUS];
59462306a36Sopenharmony_ci	struct vm_gic v;
59562306a36Sopenharmony_ci	uint64_t addr;
59662306a36Sopenharmony_ci	int its_fd, ret;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
59962306a36Sopenharmony_ci	its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	addr = 0x401000;
60262306a36Sopenharmony_ci	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
60362306a36Sopenharmony_ci				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
60462306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EINVAL,
60562306a36Sopenharmony_ci		"ITS region with misaligned address");
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	addr = max_phys_size;
60862306a36Sopenharmony_ci	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
60962306a36Sopenharmony_ci				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
61062306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == E2BIG,
61162306a36Sopenharmony_ci		"register ITS region with base address beyond IPA range");
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	addr = max_phys_size - 0x10000;
61462306a36Sopenharmony_ci	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
61562306a36Sopenharmony_ci				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
61662306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == E2BIG,
61762306a36Sopenharmony_ci		"Half of ITS region is beyond IPA range");
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* This one succeeds setting the ITS base */
62062306a36Sopenharmony_ci	addr = 0x400000;
62162306a36Sopenharmony_ci	kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
62262306a36Sopenharmony_ci			    KVM_VGIC_ITS_ADDR_TYPE, &addr);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	addr = 0x300000;
62562306a36Sopenharmony_ci	ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
62662306a36Sopenharmony_ci				    KVM_VGIC_ITS_ADDR_TYPE, &addr);
62762306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == EEXIST, "ITS base set again");
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	close(its_fd);
63062306a36Sopenharmony_ci	vm_gic_destroy(&v);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci/*
63462306a36Sopenharmony_ci * Returns 0 if it's possible to create GIC device of a given type (V2 or V3).
63562306a36Sopenharmony_ci */
63662306a36Sopenharmony_ciint test_kvm_device(uint32_t gic_dev_type)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct kvm_vcpu *vcpus[NR_VCPUS];
63962306a36Sopenharmony_ci	struct vm_gic v;
64062306a36Sopenharmony_ci	uint32_t other;
64162306a36Sopenharmony_ci	int ret;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* try to create a non existing KVM device */
64662306a36Sopenharmony_ci	ret = __kvm_test_create_device(v.vm, 0);
64762306a36Sopenharmony_ci	TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/* trial mode */
65062306a36Sopenharmony_ci	ret = __kvm_test_create_device(v.vm, gic_dev_type);
65162306a36Sopenharmony_ci	if (ret)
65262306a36Sopenharmony_ci		return ret;
65362306a36Sopenharmony_ci	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	ret = __kvm_create_device(v.vm, gic_dev_type);
65662306a36Sopenharmony_ci	TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/* try to create the other gic_dev_type */
65962306a36Sopenharmony_ci	other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3
66062306a36Sopenharmony_ci					     : KVM_DEV_TYPE_ARM_VGIC_V2;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (!__kvm_test_create_device(v.vm, other)) {
66362306a36Sopenharmony_ci		ret = __kvm_create_device(v.vm, other);
66462306a36Sopenharmony_ci		TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),
66562306a36Sopenharmony_ci				"create GIC device while other version exists");
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	vm_gic_destroy(&v);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	return 0;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_civoid run_tests(uint32_t gic_dev_type)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	test_vcpus_then_vgic(gic_dev_type);
67662306a36Sopenharmony_ci	test_vgic_then_vcpus(gic_dev_type);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (VGIC_DEV_IS_V3(gic_dev_type)) {
67962306a36Sopenharmony_ci		test_v3_new_redist_regions();
68062306a36Sopenharmony_ci		test_v3_typer_accesses();
68162306a36Sopenharmony_ci		test_v3_last_bit_redist_regions();
68262306a36Sopenharmony_ci		test_v3_last_bit_single_rdist();
68362306a36Sopenharmony_ci		test_v3_redist_ipa_range_check_at_vcpu_run();
68462306a36Sopenharmony_ci		test_v3_its_region();
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ciint main(int ac, char **av)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	int ret;
69162306a36Sopenharmony_ci	int pa_bits;
69262306a36Sopenharmony_ci	int cnt_impl = 0;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
69562306a36Sopenharmony_ci	max_phys_size = 1ULL << pa_bits;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V3);
69862306a36Sopenharmony_ci	if (!ret) {
69962306a36Sopenharmony_ci		pr_info("Running GIC_v3 tests.\n");
70062306a36Sopenharmony_ci		run_tests(KVM_DEV_TYPE_ARM_VGIC_V3);
70162306a36Sopenharmony_ci		cnt_impl++;
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V2);
70562306a36Sopenharmony_ci	if (!ret) {
70662306a36Sopenharmony_ci		pr_info("Running GIC_v2 tests.\n");
70762306a36Sopenharmony_ci		run_tests(KVM_DEV_TYPE_ARM_VGIC_V2);
70862306a36Sopenharmony_ci		cnt_impl++;
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (!cnt_impl) {
71262306a36Sopenharmony_ci		print_skip("No GICv2 nor GICv3 support");
71362306a36Sopenharmony_ci		exit(KSFT_SKIP);
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci	return 0;
71662306a36Sopenharmony_ci}
717