Path: blob/master/tools/testing/selftests/kvm/arm64/vgic_init.c
38237 views
// SPDX-License-Identifier: GPL-2.01/*2* vgic init sequence tests3*4* Copyright (C) 2020, Red Hat, Inc.5*/6#include <linux/kernel.h>7#include <sys/syscall.h>8#include <asm/kvm.h>9#include <asm/kvm_para.h>1011#include <arm64/gic_v3.h>1213#include "test_util.h"14#include "kvm_util.h"15#include "processor.h"16#include "vgic.h"17#include "gic_v3.h"1819#define NR_VCPUS 42021#define REG_OFFSET(vcpu, offset) (((uint64_t)vcpu << 32) | offset)2223#define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2)24#define VGIC_DEV_IS_V3(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V3)2526struct vm_gic {27struct kvm_vm *vm;28int gic_fd;29uint32_t gic_dev_type;30};3132static uint64_t max_phys_size;3334/*35* Helpers to access a redistributor register and verify the ioctl() failed or36* succeeded as expected, and provided the correct value on success.37*/38static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset,39int want, const char *msg)40{41uint32_t ignored_val;42int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,43REG_OFFSET(vcpu, offset), &ignored_val);4445TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want);46}4748static void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t want,49const char *msg)50{51uint32_t val;5253kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,54REG_OFFSET(vcpu, offset), &val);55TEST_ASSERT(val == want, "%s; want '0x%x', got '0x%x'", msg, want, val);56}5758/* dummy guest code */59static void guest_code(void)60{61GUEST_SYNC(0);62GUEST_SYNC(1);63GUEST_SYNC(2);64GUEST_DONE();65}6667/* we don't want to assert on run execution, hence that helper */68static int run_vcpu(struct kvm_vcpu *vcpu)69{70return __vcpu_run(vcpu) ? -errno : 0;71}7273static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type,74uint32_t nr_vcpus,75struct kvm_vcpu *vcpus[])76{77struct vm_gic v;7879v.gic_dev_type = gic_dev_type;80v.vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);81v.gic_fd = kvm_create_device(v.vm, gic_dev_type);8283return v;84}8586static struct vm_gic vm_gic_create_barebones(uint32_t gic_dev_type)87{88struct vm_gic v;8990v.gic_dev_type = gic_dev_type;91v.vm = vm_create_barebones();92v.gic_fd = kvm_create_device(v.vm, gic_dev_type);9394return v;95}969798static void vm_gic_destroy(struct vm_gic *v)99{100close(v->gic_fd);101kvm_vm_free(v->vm);102}103104struct vgic_region_attr {105uint64_t attr;106uint64_t size;107uint64_t alignment;108};109110struct vgic_region_attr gic_v3_dist_region = {111.attr = KVM_VGIC_V3_ADDR_TYPE_DIST,112.size = 0x10000,113.alignment = 0x10000,114};115116struct vgic_region_attr gic_v3_redist_region = {117.attr = KVM_VGIC_V3_ADDR_TYPE_REDIST,118.size = NR_VCPUS * 0x20000,119.alignment = 0x10000,120};121122struct vgic_region_attr gic_v2_dist_region = {123.attr = KVM_VGIC_V2_ADDR_TYPE_DIST,124.size = 0x1000,125.alignment = 0x1000,126};127128struct vgic_region_attr gic_v2_cpu_region = {129.attr = KVM_VGIC_V2_ADDR_TYPE_CPU,130.size = 0x2000,131.alignment = 0x1000,132};133134/**135* Helper routine that performs KVM device tests in general. Eventually the136* ARM_VGIC (GICv2 or GICv3) device gets created with an overlapping137* DIST/REDIST (or DIST/CPUIF for GICv2). Assumption is 4 vcpus are going to be138* used hence the overlap. In the case of GICv3, A RDIST region is set at @0x0139* and a DIST region is set @0x70000. The GICv2 case sets a CPUIF @0x0 and a140* DIST region @0x1000.141*/142static void subtest_dist_rdist(struct vm_gic *v)143{144int ret;145uint64_t addr;146struct vgic_region_attr rdist; /* CPU interface in GICv2*/147struct vgic_region_attr dist;148149rdist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_redist_region150: gic_v2_cpu_region;151dist = VGIC_DEV_IS_V3(v->gic_dev_type) ? gic_v3_dist_region152: gic_v2_dist_region;153154/* Check existing group/attributes */155kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, dist.attr);156157kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, rdist.attr);158159/* check non existing attribute */160ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, -1);161TEST_ASSERT(ret && errno == ENXIO, "attribute not supported");162163/* misaligned DIST and REDIST address settings */164addr = dist.alignment / 0x10;165ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,166dist.attr, &addr);167TEST_ASSERT(ret && errno == EINVAL, "GIC dist base not aligned");168169addr = rdist.alignment / 0x10;170ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,171rdist.attr, &addr);172TEST_ASSERT(ret && errno == EINVAL, "GIC redist/cpu base not aligned");173174/* out of range address */175addr = max_phys_size;176ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,177dist.attr, &addr);178TEST_ASSERT(ret && errno == E2BIG, "dist address beyond IPA limit");179180ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,181rdist.attr, &addr);182TEST_ASSERT(ret && errno == E2BIG, "redist address beyond IPA limit");183184/* Space for half a rdist (a rdist is: 2 * rdist.alignment). */185addr = max_phys_size - dist.alignment;186ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,187rdist.attr, &addr);188TEST_ASSERT(ret && errno == E2BIG,189"half of the redist is beyond IPA limit");190191/* set REDIST base address @0x0*/192addr = 0x00000;193kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,194rdist.attr, &addr);195196/* Attempt to create a second legacy redistributor region */197addr = 0xE0000;198ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,199rdist.attr, &addr);200TEST_ASSERT(ret && errno == EEXIST, "GIC redist base set again");201202ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,203KVM_VGIC_V3_ADDR_TYPE_REDIST);204if (!ret) {205/* Attempt to mix legacy and new redistributor regions */206addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 0, 0);207ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,208KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);209TEST_ASSERT(ret && errno == EINVAL,210"attempt to mix GICv3 REDIST and REDIST_REGION");211}212213/*214* Set overlapping DIST / REDIST, cannot be detected here. Will be detected215* on first vcpu run instead.216*/217addr = rdist.size - rdist.alignment;218kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,219dist.attr, &addr);220}221222/* Test the new REDIST region API */223static void subtest_v3_redist_regions(struct vm_gic *v)224{225uint64_t addr, expected_addr;226int ret;227228ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,229KVM_VGIC_V3_ADDR_TYPE_REDIST);230TEST_ASSERT(!ret, "Multiple redist regions advertised");231232addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 2, 0);233ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,234KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);235TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with flags != 0");236237addr = REDIST_REGION_ATTR_ADDR(0, 0x100000, 0, 0);238ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,239KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);240TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with count== 0");241242addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);243ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,244KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);245TEST_ASSERT(ret && errno == EINVAL,246"attempt to register the first rdist region with index != 0");247248addr = REDIST_REGION_ATTR_ADDR(2, 0x201000, 0, 1);249ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,250KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);251TEST_ASSERT(ret && errno == EINVAL, "rdist region with misaligned address");252253addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);254kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,255KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);256257addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1);258ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,259KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);260TEST_ASSERT(ret && errno == EINVAL, "register an rdist region with already used index");261262addr = REDIST_REGION_ATTR_ADDR(1, 0x210000, 0, 2);263ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,264KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);265TEST_ASSERT(ret && errno == EINVAL,266"register an rdist region overlapping with another one");267268addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 2);269ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,270KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);271TEST_ASSERT(ret && errno == EINVAL, "register redist region with index not +1");272273addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);274kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,275KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);276277addr = REDIST_REGION_ATTR_ADDR(1, max_phys_size, 0, 2);278ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,279KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);280TEST_ASSERT(ret && errno == E2BIG,281"register redist region with base address beyond IPA range");282283/* The last redist is above the pa range. */284addr = REDIST_REGION_ATTR_ADDR(2, max_phys_size - 0x30000, 0, 2);285ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,286KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);287TEST_ASSERT(ret && errno == E2BIG,288"register redist region with top address beyond IPA range");289290addr = 0x260000;291ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,292KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);293TEST_ASSERT(ret && errno == EINVAL,294"Mix KVM_VGIC_V3_ADDR_TYPE_REDIST and REDIST_REGION");295296/*297* Now there are 2 redist regions:298* region 0 @ 0x200000 2 redists299* region 1 @ 0x240000 1 redist300* Attempt to read their characteristics301*/302303addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 0);304expected_addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);305ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,306KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);307TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #0");308309addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 1);310expected_addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1);311ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,312KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);313TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #1");314315addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 2);316ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,317KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);318TEST_ASSERT(ret && errno == ENOENT, "read characteristics of non existing region");319320addr = 0x260000;321kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,322KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);323324addr = REDIST_REGION_ATTR_ADDR(1, 0x260000, 0, 2);325ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,326KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);327TEST_ASSERT(ret && errno == EINVAL, "register redist region colliding with dist");328}329330/*331* VGIC KVM device is created and initialized before the secondary CPUs332* get created333*/334static void test_vgic_then_vcpus(uint32_t gic_dev_type)335{336struct kvm_vcpu *vcpus[NR_VCPUS];337struct vm_gic v;338int ret, i;339340v = vm_gic_create_with_vcpus(gic_dev_type, 1, vcpus);341342subtest_dist_rdist(&v);343344/* Add the rest of the VCPUs */345for (i = 1; i < NR_VCPUS; ++i)346vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);347348ret = run_vcpu(vcpus[3]);349TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");350351vm_gic_destroy(&v);352}353354/* All the VCPUs are created before the VGIC KVM device gets initialized */355static void test_vcpus_then_vgic(uint32_t gic_dev_type)356{357struct kvm_vcpu *vcpus[NR_VCPUS];358struct vm_gic v;359int ret;360361v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, vcpus);362363subtest_dist_rdist(&v);364365ret = run_vcpu(vcpus[3]);366TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run");367368vm_gic_destroy(&v);369}370371#define KVM_VGIC_V2_ATTR(offset, cpu) \372(FIELD_PREP(KVM_DEV_ARM_VGIC_OFFSET_MASK, offset) | \373FIELD_PREP(KVM_DEV_ARM_VGIC_CPUID_MASK, cpu))374375#define GIC_CPU_CTRL 0x00376377static void test_v2_uaccess_cpuif_no_vcpus(void)378{379struct vm_gic v;380u64 val = 0;381int ret;382383v = vm_gic_create_barebones(KVM_DEV_TYPE_ARM_VGIC_V2);384subtest_dist_rdist(&v);385386ret = __kvm_has_device_attr(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,387KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0));388TEST_ASSERT(ret && errno == EINVAL,389"accessed non-existent CPU interface, want errno: %i",390EINVAL);391ret = __kvm_device_attr_get(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,392KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val);393TEST_ASSERT(ret && errno == EINVAL,394"accessed non-existent CPU interface, want errno: %i",395EINVAL);396ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,397KVM_VGIC_V2_ATTR(GIC_CPU_CTRL, 0), &val);398TEST_ASSERT(ret && errno == EINVAL,399"accessed non-existent CPU interface, want errno: %i",400EINVAL);401402vm_gic_destroy(&v);403}404405static void test_v3_new_redist_regions(void)406{407struct kvm_vcpu *vcpus[NR_VCPUS];408void *dummy = NULL;409struct vm_gic v;410uint64_t addr;411int ret;412413v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);414subtest_v3_redist_regions(&v);415kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,416KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);417418ret = run_vcpu(vcpus[3]);419TEST_ASSERT(ret == -ENXIO, "running without sufficient number of rdists");420vm_gic_destroy(&v);421422/* step2 */423424v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);425subtest_v3_redist_regions(&v);426427addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);428kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,429KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);430431ret = run_vcpu(vcpus[3]);432TEST_ASSERT(ret == -EBUSY, "running without vgic explicit init");433434vm_gic_destroy(&v);435436/* step 3 */437438v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);439subtest_v3_redist_regions(&v);440441ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,442KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy);443TEST_ASSERT(ret && errno == EFAULT,444"register a third region allowing to cover the 4 vcpus");445446addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);447kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,448KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);449450kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,451KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);452453ret = run_vcpu(vcpus[3]);454TEST_ASSERT(!ret, "vcpu run");455456vm_gic_destroy(&v);457}458459static void test_v3_typer_accesses(void)460{461struct vm_gic v;462uint64_t addr;463int ret, i;464465v.vm = vm_create(NR_VCPUS);466(void)vm_vcpu_add(v.vm, 0, guest_code);467468v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);469470(void)vm_vcpu_add(v.vm, 3, guest_code);471472v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL,473"attempting to read GICR_TYPER of non created vcpu");474475(void)vm_vcpu_add(v.vm, 1, guest_code);476477v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY,478"read GICR_TYPER before GIC initialized");479480(void)vm_vcpu_add(v.vm, 2, guest_code);481482kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,483KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);484485for (i = 0; i < NR_VCPUS ; i++) {486v3_redist_reg_get(v.gic_fd, i, GICR_TYPER, i * 0x100,487"read GICR_TYPER before rdist region setting");488}489490addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0);491kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,492KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);493494/* The 2 first rdists should be put there (vcpu 0 and 3) */495v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x0, "read typer of rdist #0");496v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #1");497498addr = REDIST_REGION_ATTR_ADDR(10, 0x100000, 0, 1);499ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,500KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);501TEST_ASSERT(ret && errno == EINVAL, "collision with previous rdist region");502503v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100,504"no redist region attached to vcpu #1 yet, last cannot be returned");505v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200,506"no redist region attached to vcpu #2, last cannot be returned");507508addr = REDIST_REGION_ATTR_ADDR(10, 0x20000, 0, 1);509kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,510KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);511512v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");513v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210,514"read typer of rdist #1, last properly returned");515516vm_gic_destroy(&v);517}518519static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus,520uint32_t vcpuids[])521{522struct vm_gic v;523int i;524525v.vm = vm_create(nr_vcpus);526for (i = 0; i < nr_vcpus; i++)527vm_vcpu_add(v.vm, vcpuids[i], guest_code);528529v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3);530531return v;532}533534/**535* Test GICR_TYPER last bit with new redist regions536* rdist regions #1 and #2 are contiguous537* rdist region #0 @0x100000 2 rdist capacity538* rdists: 0, 3 (Last)539* rdist region #1 @0x240000 2 rdist capacity540* rdists: 5, 4 (Last)541* rdist region #2 @0x200000 2 rdist capacity542* rdists: 1, 2543*/544static void test_v3_last_bit_redist_regions(void)545{546uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };547struct vm_gic v;548uint64_t addr;549550v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);551552kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,553KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);554555addr = REDIST_REGION_ATTR_ADDR(2, 0x100000, 0, 0);556kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,557KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);558559addr = REDIST_REGION_ATTR_ADDR(2, 0x240000, 0, 1);560kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,561KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);562563addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 2);564kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,565KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);566567v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");568v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1");569v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200, "read typer of rdist #2");570v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #3");571v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #5");572v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, 0x410, "read typer of rdist #4");573574vm_gic_destroy(&v);575}576577/* Test last bit with legacy region */578static void test_v3_last_bit_single_rdist(void)579{580uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 };581struct vm_gic v;582uint64_t addr;583584v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids);585586kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,587KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);588589addr = 0x10000;590kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,591KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);592593v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0");594v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x300, "read typer of rdist #1");595v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #2");596v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #3");597v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210, "read typer of rdist #3");598599vm_gic_destroy(&v);600}601602/* Uses the legacy REDIST region API. */603static void test_v3_redist_ipa_range_check_at_vcpu_run(void)604{605struct kvm_vcpu *vcpus[NR_VCPUS];606struct vm_gic v;607int ret, i;608uint64_t addr;609610v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus);611612/* Set space for 3 redists, we have 1 vcpu, so this succeeds. */613addr = max_phys_size - (3 * 2 * 0x10000);614kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,615KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr);616617addr = 0x00000;618kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,619KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);620621/* Add the rest of the VCPUs */622for (i = 1; i < NR_VCPUS; ++i)623vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);624625kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,626KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);627628/* Attempt to run a vcpu without enough redist space. */629ret = run_vcpu(vcpus[2]);630TEST_ASSERT(ret && errno == EINVAL,631"redist base+size above PA range detected on 1st vcpu run");632633vm_gic_destroy(&v);634}635636static void test_v3_its_region(void)637{638struct kvm_vcpu *vcpus[NR_VCPUS];639struct vm_gic v;640uint64_t addr;641int its_fd, ret;642643v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);644its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS);645646addr = 0x401000;647ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,648KVM_VGIC_ITS_ADDR_TYPE, &addr);649TEST_ASSERT(ret && errno == EINVAL,650"ITS region with misaligned address");651652addr = max_phys_size;653ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,654KVM_VGIC_ITS_ADDR_TYPE, &addr);655TEST_ASSERT(ret && errno == E2BIG,656"register ITS region with base address beyond IPA range");657658addr = max_phys_size - 0x10000;659ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,660KVM_VGIC_ITS_ADDR_TYPE, &addr);661TEST_ASSERT(ret && errno == E2BIG,662"Half of ITS region is beyond IPA range");663664/* This one succeeds setting the ITS base */665addr = 0x400000;666kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,667KVM_VGIC_ITS_ADDR_TYPE, &addr);668669addr = 0x300000;670ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,671KVM_VGIC_ITS_ADDR_TYPE, &addr);672TEST_ASSERT(ret && errno == EEXIST, "ITS base set again");673674close(its_fd);675vm_gic_destroy(&v);676}677678static void test_v3_nassgicap(void)679{680struct kvm_vcpu *vcpus[NR_VCPUS];681bool has_nassgicap;682struct vm_gic vm;683u32 typer2;684int ret;685686vm = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);687kvm_device_attr_get(vm.gic_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,688GICD_TYPER2, &typer2);689has_nassgicap = typer2 & GICD_TYPER2_nASSGIcap;690691typer2 |= GICD_TYPER2_nASSGIcap;692ret = __kvm_device_attr_set(vm.gic_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,693GICD_TYPER2, &typer2);694if (has_nassgicap)695TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_DEVICE_ATTR_SET, ret));696else697TEST_ASSERT(ret && errno == EINVAL,698"Enabled nASSGIcap even though it's unavailable");699700typer2 &= ~GICD_TYPER2_nASSGIcap;701kvm_device_attr_set(vm.gic_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,702GICD_TYPER2, &typer2);703704kvm_device_attr_set(vm.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,705KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);706707typer2 ^= GICD_TYPER2_nASSGIcap;708ret = __kvm_device_attr_set(vm.gic_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,709GICD_TYPER2, &typer2);710TEST_ASSERT(ret && errno == EBUSY,711"Changed nASSGIcap after initializing the VGIC");712713vm_gic_destroy(&vm);714}715716/*717* Returns 0 if it's possible to create GIC device of a given type (V2 or V3).718*/719int test_kvm_device(uint32_t gic_dev_type)720{721struct kvm_vcpu *vcpus[NR_VCPUS];722struct vm_gic v;723uint32_t other;724int ret;725726v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);727728/* try to create a non existing KVM device */729ret = __kvm_test_create_device(v.vm, 0);730TEST_ASSERT(ret && errno == ENODEV, "unsupported device");731732/* trial mode */733ret = __kvm_test_create_device(v.vm, gic_dev_type);734if (ret)735return ret;736v.gic_fd = kvm_create_device(v.vm, gic_dev_type);737738ret = __kvm_create_device(v.vm, gic_dev_type);739TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");740741/* try to create the other gic_dev_type */742other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3743: KVM_DEV_TYPE_ARM_VGIC_V2;744745if (!__kvm_test_create_device(v.vm, other)) {746ret = __kvm_create_device(v.vm, other);747TEST_ASSERT(ret < 0 && (errno == EINVAL || errno == EEXIST),748"create GIC device while other version exists");749}750751vm_gic_destroy(&v);752753return 0;754}755756struct sr_def {757const char *name;758u32 encoding;759};760761#define PACK_SR(r) \762((sys_reg_Op0(r) << 14) | \763(sys_reg_Op1(r) << 11) | \764(sys_reg_CRn(r) << 7) | \765(sys_reg_CRm(r) << 3) | \766(sys_reg_Op2(r)))767768#define SR(r) \769{ \770.name = #r, \771.encoding = r, \772}773774static const struct sr_def sysregs_el1[] = {775SR(SYS_ICC_PMR_EL1),776SR(SYS_ICC_BPR0_EL1),777SR(SYS_ICC_AP0R0_EL1),778SR(SYS_ICC_AP0R1_EL1),779SR(SYS_ICC_AP0R2_EL1),780SR(SYS_ICC_AP0R3_EL1),781SR(SYS_ICC_AP1R0_EL1),782SR(SYS_ICC_AP1R1_EL1),783SR(SYS_ICC_AP1R2_EL1),784SR(SYS_ICC_AP1R3_EL1),785SR(SYS_ICC_BPR1_EL1),786SR(SYS_ICC_CTLR_EL1),787SR(SYS_ICC_SRE_EL1),788SR(SYS_ICC_IGRPEN0_EL1),789SR(SYS_ICC_IGRPEN1_EL1),790};791792static const struct sr_def sysregs_el2[] = {793SR(SYS_ICH_AP0R0_EL2),794SR(SYS_ICH_AP0R1_EL2),795SR(SYS_ICH_AP0R2_EL2),796SR(SYS_ICH_AP0R3_EL2),797SR(SYS_ICH_AP1R0_EL2),798SR(SYS_ICH_AP1R1_EL2),799SR(SYS_ICH_AP1R2_EL2),800SR(SYS_ICH_AP1R3_EL2),801SR(SYS_ICH_HCR_EL2),802SR(SYS_ICC_SRE_EL2),803SR(SYS_ICH_VTR_EL2),804SR(SYS_ICH_VMCR_EL2),805SR(SYS_ICH_LR0_EL2),806SR(SYS_ICH_LR1_EL2),807SR(SYS_ICH_LR2_EL2),808SR(SYS_ICH_LR3_EL2),809SR(SYS_ICH_LR4_EL2),810SR(SYS_ICH_LR5_EL2),811SR(SYS_ICH_LR6_EL2),812SR(SYS_ICH_LR7_EL2),813SR(SYS_ICH_LR8_EL2),814SR(SYS_ICH_LR9_EL2),815SR(SYS_ICH_LR10_EL2),816SR(SYS_ICH_LR11_EL2),817SR(SYS_ICH_LR12_EL2),818SR(SYS_ICH_LR13_EL2),819SR(SYS_ICH_LR14_EL2),820SR(SYS_ICH_LR15_EL2),821};822823static void test_sysreg_array(int gic, const struct sr_def *sr, int nr,824int (*check)(int, const struct sr_def *, const char *))825{826for (int i = 0; i < nr; i++) {827u64 val;828u64 attr;829int ret;830831/* Assume MPIDR_EL1.Aff*=0 */832attr = PACK_SR(sr[i].encoding);833834/*835* The API is braindead. A register can be advertised as836* available, and yet not be readable or writable.837* ICC_APnR{1,2,3}_EL1 are examples of such non-sense, and838* ICH_APnR{1,2,3}_EL2 do follow suit for consistency.839*840* On the bright side, no known HW is implementing more than841* 5 bits of priority, so we're safe. Sort of...842*/843ret = __kvm_has_device_attr(gic, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,844attr);845TEST_ASSERT(ret == 0, "%s unavailable", sr[i].name);846847/* Check that we can write back what we read */848ret = __kvm_device_attr_get(gic, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,849attr, &val);850TEST_ASSERT(ret == 0 || !check(gic, &sr[i], "read"), "%s unreadable", sr[i].name);851ret = __kvm_device_attr_set(gic, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,852attr, &val);853TEST_ASSERT(ret == 0 || !check(gic, &sr[i], "write"), "%s unwritable", sr[i].name);854}855}856857static u8 get_ctlr_pribits(int gic)858{859int ret;860u64 val;861u8 pri;862863ret = __kvm_device_attr_get(gic, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,864PACK_SR(SYS_ICC_CTLR_EL1), &val);865TEST_ASSERT(ret == 0, "ICC_CTLR_EL1 unreadable");866867pri = FIELD_GET(ICC_CTLR_EL1_PRI_BITS_MASK, val) + 1;868TEST_ASSERT(pri >= 5 && pri <= 7, "Bad pribits %d", pri);869870return pri;871}872873static int check_unaccessible_el1_regs(int gic, const struct sr_def *sr, const char *what)874{875switch (sr->encoding) {876case SYS_ICC_AP0R1_EL1:877case SYS_ICC_AP1R1_EL1:878if (get_ctlr_pribits(gic) >= 6)879return -EINVAL;880break;881case SYS_ICC_AP0R2_EL1:882case SYS_ICC_AP0R3_EL1:883case SYS_ICC_AP1R2_EL1:884case SYS_ICC_AP1R3_EL1:885if (get_ctlr_pribits(gic) == 7)886return 0;887break;888default:889return -EINVAL;890}891892pr_info("SKIP %s for %s\n", sr->name, what);893return 0;894}895896static u8 get_vtr_pribits(int gic)897{898int ret;899u64 val;900u8 pri;901902ret = __kvm_device_attr_get(gic, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,903PACK_SR(SYS_ICH_VTR_EL2), &val);904TEST_ASSERT(ret == 0, "ICH_VTR_EL2 unreadable");905906pri = FIELD_GET(ICH_VTR_EL2_PRIbits, val) + 1;907TEST_ASSERT(pri >= 5 && pri <= 7, "Bad pribits %d", pri);908909return pri;910}911912static int check_unaccessible_el2_regs(int gic, const struct sr_def *sr, const char *what)913{914switch (sr->encoding) {915case SYS_ICH_AP0R1_EL2:916case SYS_ICH_AP1R1_EL2:917if (get_vtr_pribits(gic) >= 6)918return -EINVAL;919break;920case SYS_ICH_AP0R2_EL2:921case SYS_ICH_AP0R3_EL2:922case SYS_ICH_AP1R2_EL2:923case SYS_ICH_AP1R3_EL2:924if (get_vtr_pribits(gic) == 7)925return -EINVAL;926break;927default:928return -EINVAL;929}930931pr_info("SKIP %s for %s\n", sr->name, what);932return 0;933}934935static void test_v3_sysregs(void)936{937struct kvm_vcpu_init init = {};938struct kvm_vcpu *vcpu;939struct kvm_vm *vm;940u32 feat = 0;941int gic;942943if (kvm_check_cap(KVM_CAP_ARM_EL2))944feat |= BIT(KVM_ARM_VCPU_HAS_EL2);945946vm = vm_create(1);947948vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);949init.features[0] |= feat;950951vcpu = aarch64_vcpu_add(vm, 0, &init, NULL);952TEST_ASSERT(vcpu, "Can't create a vcpu?");953954gic = kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3);955TEST_ASSERT(gic >= 0, "No GIC???");956957kvm_device_attr_set(gic, KVM_DEV_ARM_VGIC_GRP_CTRL,958KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);959960test_sysreg_array(gic, sysregs_el1, ARRAY_SIZE(sysregs_el1), check_unaccessible_el1_regs);961if (feat)962test_sysreg_array(gic, sysregs_el2, ARRAY_SIZE(sysregs_el2), check_unaccessible_el2_regs);963else964pr_info("SKIP EL2 registers, not available\n");965966close(gic);967kvm_vm_free(vm);968}969970void run_tests(uint32_t gic_dev_type)971{972test_vcpus_then_vgic(gic_dev_type);973test_vgic_then_vcpus(gic_dev_type);974975if (VGIC_DEV_IS_V2(gic_dev_type))976test_v2_uaccess_cpuif_no_vcpus();977978if (VGIC_DEV_IS_V3(gic_dev_type)) {979test_v3_new_redist_regions();980test_v3_typer_accesses();981test_v3_last_bit_redist_regions();982test_v3_last_bit_single_rdist();983test_v3_redist_ipa_range_check_at_vcpu_run();984test_v3_its_region();985test_v3_sysregs();986test_v3_nassgicap();987}988}989990int main(int ac, char **av)991{992int ret;993int pa_bits;994int cnt_impl = 0;995996test_disable_default_vgic();997998pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;999max_phys_size = 1ULL << pa_bits;10001001ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V3);1002if (!ret) {1003pr_info("Running GIC_v3 tests.\n");1004run_tests(KVM_DEV_TYPE_ARM_VGIC_V3);1005cnt_impl++;1006}10071008ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V2);1009if (!ret) {1010pr_info("Running GIC_v2 tests.\n");1011run_tests(KVM_DEV_TYPE_ARM_VGIC_V2);1012cnt_impl++;1013}10141015if (!cnt_impl) {1016print_skip("No GICv2 nor GICv3 support");1017exit(KSFT_SKIP);1018}1019return 0;1020}102110221023