M tests/kvm/device.cpp => tests/kvm/device.cpp +70 -7
@@ 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<uintptr_t>(&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<uint64_t>(data); // bad address
+
+ REQUIRE_THROWS_WITH(device.get_attr(attr), "Bad address");
+
+ attr.addr = reinterpret_cast<uintptr_t>(&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
M tests/kvm/vcpu.cpp => tests/kvm/vcpu.cpp +4 -4
@@ 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();