~satchmo/libvmm

0df52868c3ef00c335bd4792a0b302534dd06230 — Jason Phan 3 months ago d9d8967
kvm: Add aarch64 device creation test
2 files changed, 74 insertions(+), 11 deletions(-)

M tests/kvm/device.cpp
M tests/kvm/vcpu.cpp
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();