From 0df52868c3ef00c335bd4792a0b302534dd06230 Mon Sep 17 00:00:00 2001 From: Jason Phan Date: Fri, 27 Nov 2020 22:06:22 -0600 Subject: [PATCH] kvm: Add aarch64 device creation test --- tests/kvm/device.cpp | 77 ++++++++++++++++++++++++++++++++++++++++---- tests/kvm/vcpu.cpp | 8 ++--- 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/tests/kvm/device.cpp b/tests/kvm/device.cpp index ff5ffa2..ca2df45 100644 --- a/tests/kvm/device.cpp +++ b/tests/kvm/device.cpp @@ -5,13 +5,13 @@ #include "vmm/kvm/kvm.hpp" #if defined(__i386__) || defined(__x86_64__) -// NOTE: For some unknown reason, making 2 -// `vm.device(KVM_DEV_TYPE_VFIO, KVM_CREATE_DEVICE_TEST)` calls (and only -// binding the second one to a variable) causes `has_attr()` and co to -// fail with "Invalid argument" instead of "Inappropriate ioctl." This is -// true even if the calls were made in separate test cases... Because of -// this, we can't exactly test just device creation. -TEST_CASE("Fake device attributes") { +// FIXME: For some reason, making 2 +// `vm.device(KVM_DEV_TYPE_VFIO, KVM_CREATE_DEVICE_TEST)` calls (and only +// binding the second one to a variable) causes `has_attr()` and co to +// fail with "Invalid argument" instead of "Inappropriate ioctl." This is +// true even if the calls were made in separate test cases... Because of +// this, we can't exactly test just device creation. +TEST_CASE("Device creation") { auto kvm = vmm::kvm::system{}; auto vm = kvm.vm(); @@ -35,3 +35,66 @@ TEST_CASE("Fake device attributes") { REQUIRE_THROWS_WITH(device.set_attr(attr), "Inappropriate ioctl for device"); } #endif + +#if defined(__aarch64__) +// Helper function for the aarch64 test case "Device creation". +// +// The test case tries to create a vGIC2 device if creating a vGIC3 device +// failed. To avoid duplicating logic in both try/catch sections, we call out +// to this function. +auto test_device_creation(vmm::kvm::device&& device) { + // set attribute which don't apply to VGIC (i.e., expected to fail) + auto attr = kvm_device_attr { + 0, + KVM_DEV_VFIO_GROUP, + KVM_DEV_VFIO_GROUP_ADD, + 0, + }; + + REQUIRE_THROWS(device.has_attr(attr)); + + // set some attributes + const auto irqs = uint32_t{128}; + attr.group = KVM_DEV_ARM_VGIC_GRP_NR_IRQS; + attr.addr = reinterpret_cast(&irqs); + + REQUIRE_NOTHROW(device.set_attr(attr)); + + attr.group = KVM_DEV_ARM_VGIC_GRP_CTRL; + attr.attr = KVM_DEV_ARM_VGIC_CTRL_INIT; + attr.addr = 0; + + REQUIRE_NOTHROW(device.has_attr(attr)); + REQUIRE_NOTHROW(device.set_attr(attr)); + + // extract max supported # of IRQs + auto data = uint32_t{}; + + attr.group = KVM_DEV_ARM_VGIC_GRP_NR_IRQS; + attr.attr = 0; + attr.addr = static_cast(data); // bad address + + REQUIRE_THROWS_WITH(device.get_attr(attr), "Bad address"); + + attr.addr = reinterpret_cast(&data); + REQUIRE_NOTHROW(device.get_attr(attr)); + + REQUIRE(data == 128); +} + +TEST_CASE("Device creation") { + auto kvm = vmm::kvm::system{}; + auto vm = kvm.vm(); + + // Fails on aarch64 since it doesn't use MPIC, it uses the VGIC. + REQUIRE_THROWS(vm.device(KVM_DEV_TYPE_FSL_MPIC_20, KVM_CREATE_DEVICE_TEST)); + + try { + auto device = vm.device(KVM_DEV_TYPE_ARM_VGIC_V3); + test_device_creation(std::move(device)); + } catch (std::system_error& err) { + auto device = vm.device(KVM_DEV_TYPE_ARM_VGIC_V2); + test_device_creation(std::move(device)); + } +} +#endif diff --git a/tests/kvm/vcpu.cpp b/tests/kvm/vcpu.cpp index 2cee4d2..5b67b48 100644 --- a/tests/kvm/vcpu.cpp +++ b/tests/kvm/vcpu.cpp @@ -242,7 +242,7 @@ TEST_CASE("Run (arm)") { regs.rflags = 2, vcpu.set_regs(regs); - // Run vCPU + // run vCPU while (1) { auto exit = vcpu.run(); @@ -383,16 +383,16 @@ TEST_CASE("Run (x86)") { kvi.features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; vcpu.init(kvi); - // Set PC to guest address (where code is) + // set PC to guest address (where code is) auto core_reg_base = uint64_t{0x6030'0000'0010'0000}; vcpu.set_reg(core_reg_base + 2 * 32, guest_addr); - // Set x8 and x9 to addreses the guest test code needs + // set x8 and x9 to addreses the guest test code needs auto mmio_addr = uint64_t{guest_addr + mem_size}; vcpu.set_reg(core_reg_base + 2 * 8, guest_addr + 0x10000); vcpu.set_reg(core_reg_base + 2 * 9, mmio_addr); - // Run vCPU + // run vCPU while (1) { auto exit = vcpu.run(); -- 2.30.2