Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * vgic init sequence tests
0004  *
0005  * Copyright (C) 2020, Red Hat, Inc.
0006  */
0007 #define _GNU_SOURCE
0008 #include <linux/kernel.h>
0009 #include <sys/syscall.h>
0010 #include <asm/kvm.h>
0011 #include <asm/kvm_para.h>
0012 
0013 #include "test_util.h"
0014 #include "kvm_util.h"
0015 #include "processor.h"
0016 #include "vgic.h"
0017 
0018 #define NR_VCPUS        4
0019 
0020 #define REG_OFFSET(vcpu, offset) (((uint64_t)vcpu << 32) | offset)
0021 
0022 #define GICR_TYPER 0x8
0023 
0024 #define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2)
0025 #define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3)
0026 
0027 struct vm_gic {
0028     struct kvm_vm *vm;
0029     int gic_fd;
0030     uint32_t gic_dev_type;
0031 };
0032 
0033 static uint64_t max_phys_size;
0034 
0035 /*
0036  * Helpers to access a redistributor register and verify the ioctl() failed or
0037  * succeeded as expected, and provided the correct value on success.
0038  */
0039 static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset,
0040                     int want, const char *msg)
0041 {
0042     uint32_t ignored_val;
0043     int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
0044                     REG_OFFSET(vcpu, offset), &ignored_val);
0045 
0046     TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want);
0047 }
0048 
0049 static void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t want,
0050                   const char *msg)
0051 {
0052     uint32_t val;
0053 
0054     kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
0055                 REG_OFFSET(vcpu, offset), &val);
0056     TEST_ASSERT(val == want, "%s; want '0x%x', got '0x%x'", msg, want, val);
0057 }
0058 
0059 /* dummy guest code */
0060 static void guest_code(void)
0061 {
0062     GUEST_SYNC(0);
0063     GUEST_SYNC(1);
0064     GUEST_SYNC(2);
0065     GUEST_DONE();
0066 }
0067 
0068 /* we don't want to assert on run execution, hence that helper */
0069 static int run_vcpu(struct kvm_vcpu *vcpu)
0070 {
0071     ucall_init(vcpu->vm, NULL);
0072 
0073     return __vcpu_run(vcpu) ? -errno : 0;
0074 }
0075 
0076 static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type,
0077                           uint32_t nr_vcpus,
0078                           struct kvm_vcpu *vcpus[])
0079 {
0080     struct vm_gic v;
0081 
0082     v.gic_dev_type = gic_dev_type;
0083     v.vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
0084     v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
0085 
0086     return v;
0087 }
0088 
0089 static void vm_gic_destroy(struct vm_gic *v)
0090 {
0091     close(v->gic_fd);
0092     kvm_vm_free(v->vm);
0093 }
0094 
0095 struct vgic_region_attr {
0096     uint64_t attr;
0097     uint64_t size;
0098     uint64_t alignment;
0099 };
0100 
0101 struct vgic_region_attr gic_v3_dist_region = {
0102     .attr = KVM_VGIC_V3_ADDR_TYPE_DIST,
0103     .size = 0x10000,
0104     .alignment = 0x10000,
0105 };
0106 
0107 struct vgic_region_attr gic_v3_redist_region = {
0108     .attr = KVM_VGIC_V3_ADDR_TYPE_REDIST,
0109     .size = NR_VCPUS * 0x20000,
0110     .alignment = 0x10000,
0111 };
0112 
0113 struct vgic_region_attr gic_v2_dist_region = {
0114     .attr = KVM_VGIC_V2_ADDR_TYPE_DIST,
0115     .size = 0x1000,
0116     .alignment = 0x1000,
0117 };
0118 
0119 struct vgic_region_attr gic_v2_cpu_region = {
0120     .attr = KVM_VGIC_V2_ADDR_TYPE_CPU,
0121     .size = 0x2000,
0122     .alignment = 0x1000,
0123 };
0124 
0125 /**
0126  * Helper routine that performs KVM device tests in general. Eventually the
0127  * ARM_VGIC (GICv2 or GICv3) device gets created with an overlapping
0128  * DIST/REDIST (or DIST/CPUIF for GICv2). Assumption is 4 vcpus are going to be
0129  * used hence the overlap. In the case of GICv3, A RDIST region is set at @0x0
0130  * and a DIST region is set @0x70000. The GICv2 case sets a CPUIF @0x0 and a
0131  * DIST region @0x1000.
0132  */
0133 static void subtest_dist_rdist(struct vm_gic *v)
0134 {
0135     int ret;
0136     uint64_t addr;
0137     struct vgic_region_attr rdist; /* CPU interface in GICv2*/
0138     struct vgic_region_attr dist;
0139 
0140     rdist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_redist_region
0141                         : gic_v2_cpu_region;
0142     dist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_dist_region
0143                         : gic_v2_dist_region;
0144 
0145     /* Check existing group/attributes */
0146     kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, dist.attr);
0147 
0148     kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, rdist.attr);
0149 
0150     /* check non existing attribute */
0151     ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, -1);
0152     TEST_ASSERT(ret && errno == ENXIO, "attribute not supported");
0153 
0154     /* misaligned DIST and REDIST address settings */
0155     addr = dist.alignment / 0x10;
0156     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0157                     dist.attr, &addr);
0158     TEST_ASSERT(ret && errno == EINVAL, "GIC dist base not aligned");
0159 
0160     addr = rdist.alignment / 0x10;
0161     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0162                     rdist.attr, &addr);
0163     TEST_ASSERT(ret && errno == EINVAL, "GIC redist/cpu base not aligned");
0164 
0165     /* out of range address */
0166     addr = max_phys_size;
0167     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0168                     dist.attr, &addr);
0169     TEST_ASSERT(ret && errno == E2BIG, "dist address beyond IPA limit");
0170 
0171     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0172                     rdist.attr, &addr);
0173     TEST_ASSERT(ret && errno == E2BIG, "redist address beyond IPA limit");
0174 
0175     /* Space for half a rdist (a rdist is: 2 * rdist.alignment). */
0176     addr = max_phys_size - dist.alignment;
0177     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0178                     rdist.attr, &addr);
0179     TEST_ASSERT(ret && errno == E2BIG,
0180             "half of the redist is beyond IPA limit");
0181 
0182     /* set REDIST base address @0x0*/
0183     addr = 0x00000;
0184     kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0185                 rdist.attr, &addr);
0186 
0187     /* Attempt to create a second legacy redistributor region */
0188     addr = 0xE0000;
0189     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0190                     rdist.attr, &addr);
0191     TEST_ASSERT(ret && errno == EEXIST, "GIC redist base set again");
0192 
0193     ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0194                      KVM_VGIC_V3_ADDR_TYPE_REDIST);
0195     if (!ret) {
0196         /* Attempt to mix legacy and new redistributor regions */
0197         addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 0, 0);
0198         ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0199                         KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0200         TEST_ASSERT(ret && errno == EINVAL,
0201                 "attempt to mix GICv3 REDIST and REDIST_REGION");
0202     }
0203 
0204     /*
0205      * Set overlapping DIST / REDIST, cannot be detected here. Will be detected
0206      * on first vcpu run instead.
0207      */
0208     addr = rdist.size - rdist.alignment;
0209     kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0210                 dist.attr, &addr);
0211 }
0212 
0213 /* Test the new REDIST region API */
0214 static void subtest_v3_redist_regions(struct vm_gic *v)
0215 {
0216     uint64_t addr, expected_addr;
0217     int ret;
0218 
0219     ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0220                     KVM_VGIC_V3_ADDR_TYPE_REDIST);
0221     TEST_ASSERT(!ret, "Multiple redist regions advertised");
0222 
0223     addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 2, 0);
0224     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0225                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0226     TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with flags != 0");
0227 
0228     addr = REDIST_REGION_ATTR_ADDR(0, 0x100000, 0, 0);
0229     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0230                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0231     TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with count== 0");
0232 
0233     addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
0234     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0235                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0236     TEST_ASSERT(ret && errno == EINVAL,
0237             "attempt to register the first rdist region with index != 0");
0238 
0239     addr = REDIST_REGION_ATTR_ADDR(2, 0x201000, 0, 1);
0240     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0241                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0242     TEST_ASSERT(ret && errno == EINVAL, "rdist region with misaligned address");
0243 
0244     addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
0245     kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0246                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0247 
0248     addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);
0249     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0250                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0251     TEST_ASSERT(ret && errno == EINVAL, "register an rdist region with already used index");
0252 
0253     addr = REDIST_REGION_ATTR_ADDR(1, 0x210000, 0, 2);
0254     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0255                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0256     TEST_ASSERT(ret && errno == EINVAL,
0257             "register an rdist region overlapping with another one");
0258 
0259     addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 2);
0260     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0261                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0262     TEST_ASSERT(ret && errno == EINVAL, "register redist region with index not +1");
0263 
0264     addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
0265     kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0266                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0267 
0268     addr = REDIST_REGION_ATTR_ADDR(1, max_phys_size, 0, 2);
0269     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0270                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0271     TEST_ASSERT(ret && errno == E2BIG,
0272             "register redist region with base address beyond IPA range");
0273 
0274     /* The last redist is above the pa range. */
0275     addr = REDIST_REGION_ATTR_ADDR(2, max_phys_size - 0x30000, 0, 2);
0276     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0277                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0278     TEST_ASSERT(ret && errno == E2BIG,
0279             "register redist region with top address beyond IPA range");
0280 
0281     addr = 0x260000;
0282     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0283                     KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
0284     TEST_ASSERT(ret && errno == EINVAL,
0285             "Mix KVM_VGIC_V3_ADDR_TYPE_REDIST and REDIST_REGION");
0286 
0287     /*
0288      * Now there are 2 redist regions:
0289      * region 0 @ 0x200000 2 redists
0290      * region 1 @ 0x240000 1 redist
0291      * Attempt to read their characteristics
0292      */
0293 
0294     addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 0);
0295     expected_addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
0296     ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0297                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0298     TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #0");
0299 
0300     addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 1);
0301     expected_addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);
0302     ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0303                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0304     TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #1");
0305 
0306     addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 2);
0307     ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0308                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0309     TEST_ASSERT(ret && errno == ENOENT, "read characteristics of non existing region");
0310 
0311     addr = 0x260000;
0312     kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0313                 KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
0314 
0315     addr = REDIST_REGION_ATTR_ADDR(1, 0x260000, 0, 2);
0316     ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0317                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0318     TEST_ASSERT(ret && errno == EINVAL, "register redist region colliding with dist");
0319 }
0320 
0321 /*
0322  * VGIC KVM device is created and initialized before the secondary CPUs
0323  * get created
0324  */
0325 static void test_vgic_then_vcpus(uint32_t gic_dev_type)
0326 {
0327     struct kvm_vcpu *vcpus[NR_VCPUS];
0328     struct vm_gic v;
0329     int ret, i;
0330 
0331     v = vm_gic_create_with_vcpus(gic_dev_type, 1, vcpus);
0332 
0333     subtest_dist_rdist(&v);
0334 
0335     /* Add the rest of the VCPUs */
0336     for (i = 1; i < NR_VCPUS; ++i)
0337         vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
0338 
0339     ret = run_vcpu(vcpus[3]);
0340     TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
0341 
0342     vm_gic_destroy(&v);
0343 }
0344 
0345 /* All the VCPUs are created before the VGIC KVM device gets initialized */
0346 static void test_vcpus_then_vgic(uint32_t gic_dev_type)
0347 {
0348     struct kvm_vcpu *vcpus[NR_VCPUS];
0349     struct vm_gic v;
0350     int ret;
0351 
0352     v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, vcpus);
0353 
0354     subtest_dist_rdist(&v);
0355 
0356     ret = run_vcpu(vcpus[3]);
0357     TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");
0358 
0359     vm_gic_destroy(&v);
0360 }
0361 
0362 static void test_v3_new_redist_regions(void)
0363 {
0364     struct kvm_vcpu *vcpus[NR_VCPUS];
0365     void *dummy = NULL;
0366     struct vm_gic v;
0367     uint64_t addr;
0368     int ret;
0369 
0370     v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
0371     subtest_v3_redist_regions(&v);
0372     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
0373                 KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
0374 
0375     ret = run_vcpu(vcpus[3]);
0376     TEST_ASSERT(ret == -ENXIO, "running without sufficient number of rdists");
0377     vm_gic_destroy(&v);
0378 
0379     /* step2 */
0380 
0381     v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
0382     subtest_v3_redist_regions(&v);
0383 
0384     addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
0385     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0386                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0387 
0388     ret = run_vcpu(vcpus[3]);
0389     TEST_ASSERT(ret == -EBUSY, "running without vgic explicit init");
0390 
0391     vm_gic_destroy(&v);
0392 
0393     /* step 3 */
0394 
0395     v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
0396     subtest_v3_redist_regions(&v);
0397 
0398     ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0399                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy);
0400     TEST_ASSERT(ret && errno == EFAULT,
0401             "register a third region allowing to cover the 4 vcpus");
0402 
0403     addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
0404     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0405                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0406 
0407     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
0408                 KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
0409 
0410     ret = run_vcpu(vcpus[3]);
0411     TEST_ASSERT(!ret, "vcpu run");
0412 
0413     vm_gic_destroy(&v);
0414 }
0415 
0416 static void test_v3_typer_accesses(void)
0417 {
0418     struct vm_gic v;
0419     uint64_t addr;
0420     int ret, i;
0421 
0422     v.vm = vm_create(NR_VCPUS);
0423     (void)vm_vcpu_add(v.vm, 0, guest_code);
0424 
0425     v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
0426 
0427     (void)vm_vcpu_add(v.vm, 3, guest_code);
0428 
0429     v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL,
0430                 "attempting to read GICR_TYPER of non created vcpu");
0431 
0432     (void)vm_vcpu_add(v.vm, 1, guest_code);
0433 
0434     v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY,
0435                 "read GICR_TYPER before GIC initialized");
0436 
0437     (void)vm_vcpu_add(v.vm, 2, guest_code);
0438 
0439     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
0440                 KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
0441 
0442     for (i = 0; i < NR_VCPUS ; i++) {
0443         v3_redist_reg_get(v.gic_fd, i, GICR_TYPER, i * 0x100,
0444                   "read GICR_TYPER before rdist region setting");
0445     }
0446 
0447     addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);
0448     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0449                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0450 
0451     /* The 2 first rdists should be put there (vcpu 0 and 3) */
0452     v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x0, "read typer of rdist #0");
0453     v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #1");
0454 
0455     addr = REDIST_REGION_ATTR_ADDR(10, 0x100000, 0, 1);
0456     ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0457                     KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0458     TEST_ASSERT(ret && errno == EINVAL, "collision with previous rdist region");
0459 
0460     v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100,
0461               "no redist region attached to vcpu #1 yet, last cannot be returned");
0462     v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200,
0463               "no redist region attached to vcpu #2, last cannot be returned");
0464 
0465     addr = REDIST_REGION_ATTR_ADDR(10, 0x20000, 0, 1);
0466     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0467                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0468 
0469     v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
0470     v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210,
0471               "read typer of rdist #1, last properly returned");
0472 
0473     vm_gic_destroy(&v);
0474 }
0475 
0476 static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus,
0477                            uint32_t vcpuids[])
0478 {
0479     struct vm_gic v;
0480     int i;
0481 
0482     v.vm = vm_create(nr_vcpus);
0483     for (i = 0; i < nr_vcpus; i++)
0484         vm_vcpu_add(v.vm, vcpuids[i], guest_code);
0485 
0486     v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);
0487 
0488     return v;
0489 }
0490 
0491 /**
0492  * Test GICR_TYPER last bit with new redist regions
0493  * rdist regions #1 and #2 are contiguous
0494  * rdist region #0 @0x100000 2 rdist capacity
0495  *     rdists: 0, 3 (Last)
0496  * rdist region #1 @0x240000 2 rdist capacity
0497  *     rdists:  5, 4 (Last)
0498  * rdist region #2 @0x200000 2 rdist capacity
0499  *     rdists: 1, 2
0500  */
0501 static void test_v3_last_bit_redist_regions(void)
0502 {
0503     uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
0504     struct vm_gic v;
0505     uint64_t addr;
0506 
0507     v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
0508 
0509     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
0510                 KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
0511 
0512     addr = REDIST_REGION_ATTR_ADDR(2, 0x100000, 0, 0);
0513     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0514                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0515 
0516     addr = REDIST_REGION_ATTR_ADDR(2, 0x240000, 0, 1);
0517     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0518                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0519 
0520     addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 2);
0521     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0522                 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
0523 
0524     v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
0525     v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");
0526     v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200, "read typer of rdist #2");
0527     v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #3");
0528     v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #5");
0529     v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, 0x410, "read typer of rdist #4");
0530 
0531     vm_gic_destroy(&v);
0532 }
0533 
0534 /* Test last bit with legacy region */
0535 static void test_v3_last_bit_single_rdist(void)
0536 {
0537     uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };
0538     struct vm_gic v;
0539     uint64_t addr;
0540 
0541     v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);
0542 
0543     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
0544                 KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
0545 
0546     addr = 0x10000;
0547     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0548                 KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
0549 
0550     v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");
0551     v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x300, "read typer of rdist #1");
0552     v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #2");
0553     v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #3");
0554     v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210, "read typer of rdist #3");
0555 
0556     vm_gic_destroy(&v);
0557 }
0558 
0559 /* Uses the legacy REDIST region API. */
0560 static void test_v3_redist_ipa_range_check_at_vcpu_run(void)
0561 {
0562     struct kvm_vcpu *vcpus[NR_VCPUS];
0563     struct vm_gic v;
0564     int ret, i;
0565     uint64_t addr;
0566 
0567     v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus);
0568 
0569     /* Set space for 3 redists, we have 1 vcpu, so this succeeds. */
0570     addr = max_phys_size - (3 * 2 * 0x10000);
0571     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0572                 KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);
0573 
0574     addr = 0x00000;
0575     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0576                 KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
0577 
0578     /* Add the rest of the VCPUs */
0579     for (i = 1; i < NR_VCPUS; ++i)
0580         vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
0581 
0582     kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
0583                 KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
0584 
0585     /* Attempt to run a vcpu without enough redist space. */
0586     ret = run_vcpu(vcpus[2]);
0587     TEST_ASSERT(ret && errno == EINVAL,
0588         "redist base+size above PA range detected on 1st vcpu run");
0589 
0590     vm_gic_destroy(&v);
0591 }
0592 
0593 static void test_v3_its_region(void)
0594 {
0595     struct kvm_vcpu *vcpus[NR_VCPUS];
0596     struct vm_gic v;
0597     uint64_t addr;
0598     int its_fd, ret;
0599 
0600     v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
0601     its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS);
0602 
0603     addr = 0x401000;
0604     ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0605                     KVM_VGIC_ITS_ADDR_TYPE, &addr);
0606     TEST_ASSERT(ret && errno == EINVAL,
0607         "ITS region with misaligned address");
0608 
0609     addr = max_phys_size;
0610     ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0611                     KVM_VGIC_ITS_ADDR_TYPE, &addr);
0612     TEST_ASSERT(ret && errno == E2BIG,
0613         "register ITS region with base address beyond IPA range");
0614 
0615     addr = max_phys_size - 0x10000;
0616     ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0617                     KVM_VGIC_ITS_ADDR_TYPE, &addr);
0618     TEST_ASSERT(ret && errno == E2BIG,
0619         "Half of ITS region is beyond IPA range");
0620 
0621     /* This one succeeds setting the ITS base */
0622     addr = 0x400000;
0623     kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0624                 KVM_VGIC_ITS_ADDR_TYPE, &addr);
0625 
0626     addr = 0x300000;
0627     ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
0628                     KVM_VGIC_ITS_ADDR_TYPE, &addr);
0629     TEST_ASSERT(ret && errno == EEXIST, "ITS base set again");
0630 
0631     close(its_fd);
0632     vm_gic_destroy(&v);
0633 }
0634 
0635 /*
0636  * Returns 0 if it's possible to create GIC device of a given type (V2 or V3).
0637  */
0638 int test_kvm_device(uint32_t gic_dev_type)
0639 {
0640     struct kvm_vcpu *vcpus[NR_VCPUS];
0641     struct vm_gic v;
0642     uint32_t other;
0643     int ret;
0644 
0645     v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
0646 
0647     /* try to create a non existing KVM device */
0648     ret = __kvm_test_create_device(v.vm, 0);
0649     TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
0650 
0651     /* trial mode */
0652     ret = __kvm_test_create_device(v.vm, gic_dev_type);
0653     if (ret)
0654         return ret;
0655     v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
0656 
0657     ret = __kvm_create_device(v.vm, gic_dev_type);
0658     TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
0659 
0660     /* try to create the other gic_dev_type */
0661     other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3
0662                          : KVM_DEV_TYPE_ARM_VGIC_V2;
0663 
0664     if (!__kvm_test_create_device(v.vm, other)) {
0665         ret = __kvm_test_create_device(v.vm, other);
0666         TEST_ASSERT(ret && (errno == EINVAL || errno == EEXIST),
0667                 "create GIC device while other version exists");
0668     }
0669 
0670     vm_gic_destroy(&v);
0671 
0672     return 0;
0673 }
0674 
0675 void run_tests(uint32_t gic_dev_type)
0676 {
0677     test_vcpus_then_vgic(gic_dev_type);
0678     test_vgic_then_vcpus(gic_dev_type);
0679 
0680     if (VGIC_DEV_IS_V3(gic_dev_type)) {
0681         test_v3_new_redist_regions();
0682         test_v3_typer_accesses();
0683         test_v3_last_bit_redist_regions();
0684         test_v3_last_bit_single_rdist();
0685         test_v3_redist_ipa_range_check_at_vcpu_run();
0686         test_v3_its_region();
0687     }
0688 }
0689 
0690 int main(int ac, char **av)
0691 {
0692     int ret;
0693     int pa_bits;
0694     int cnt_impl = 0;
0695 
0696     pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
0697     max_phys_size = 1ULL << pa_bits;
0698 
0699     ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V3);
0700     if (!ret) {
0701         pr_info("Running GIC_v3 tests.\n");
0702         run_tests(KVM_DEV_TYPE_ARM_VGIC_V3);
0703         cnt_impl++;
0704     }
0705 
0706     ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V2);
0707     if (!ret) {
0708         pr_info("Running GIC_v2 tests.\n");
0709         run_tests(KVM_DEV_TYPE_ARM_VGIC_V2);
0710         cnt_impl++;
0711     }
0712 
0713     if (!cnt_impl) {
0714         print_skip("No GICv2 nor GICv3 support");
0715         exit(KSFT_SKIP);
0716     }
0717     return 0;
0718 }