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