blob: 9023cf8b382dfb0b25bcbf7459553438d4e328c6 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fake-msi/msi.h>
#include <lib/fake-object/object.h>
#include <lib/zx/event.h>
#include <lib/zx/msi.h>
#include <lib/zx/vmo.h>
#include <zircon/rights.h>
#include <climits>
#include <utility>
#include <fbl/ref_ptr.h>
#include <sanitizer/lsan_interface.h>
#include <zxtest/zxtest.h>
namespace {
class FakeMsiTests : public zxtest::Test {};
// If an MSI allocation goes out of scope before all the interrupts created
// off of it the dtor should assert.
TEST_F(FakeMsiTests, CleanupTest) {
zx::interrupt interrupt;
ASSERT_DEATH([&interrupt]() {
#if __has_feature(address_sanitizer) || __has_feature(leak_sanitizer)
// Suppress the leaks that come from the fact that the MSI dtor doesn't
// finish.
__lsan::ScopedDisabler suppress;
#endif
zx::msi msi;
zx::vmo vmo;
ASSERT_OK(zx::vmo::create(ZX_PAGE_SIZE, /*options=*/0, &vmo));
ASSERT_OK(vmo.set_cache_policy(ZX_CACHE_POLICY_UNCACHED_DEVICE));
ASSERT_OK(zx::msi::allocate(*zx::unowned_resource(), 2, &msi));
ASSERT_OK(zx::msi::create(msi, /*options=*/0, 0, vmo, /*vmo_offset=*/0, &interrupt));
});
}
TEST_F(FakeMsiTests, CoreTest) {
zx::msi msi;
zx::vmo vmo;
zx::interrupt int_0, int_1;
uint32_t msi_cnt = 8;
// MSI syscalls are expected to use physical VMOs, but can use contiguous, uncached, commit
zx_info_msi_t msi_info;
zx_status_t status = zx::msi::allocate(*zx::unowned_resource(ZX_HANDLE_INVALID), msi_cnt, &msi);
ASSERT_OK(status);
ASSERT_OK(zx::vmo::create(ZX_PAGE_SIZE, /*options=*/0, &vmo));
ASSERT_OK(msi.get_info(ZX_INFO_MSI, &msi_info, sizeof(msi_info), nullptr, nullptr));
ASSERT_STATUS(zx::msi::create(msi, ZX_INTERRUPT_VIRTUAL, 0, vmo, /*vmo_offset=*/0, &int_0),
ZX_ERR_INVALID_ARGS);
ASSERT_OK(vmo.set_cache_policy(ZX_CACHE_POLICY_UNCACHED_DEVICE));
// |options| must be zero.
ASSERT_STATUS(zx::msi::create(msi, ZX_INTERRUPT_VIRTUAL, 0, vmo, /*vmo_offset=*/0, &int_0),
ZX_ERR_INVALID_ARGS);
// Bad handle.
ASSERT_STATUS(zx::msi::create(*zx::unowned_msi(0x123456), /*options=*/0, /*msi_id=*/0, vmo,
/*vmo_offset=*/0, &int_0),
ZX_ERR_BAD_HANDLE);
// Invalid MSI id.
ASSERT_STATUS(
zx::msi::create(msi, /*options=*/0, /*msi_id=*/msi_cnt, vmo, /*vmo_offset=*/0, &int_0),
ZX_ERR_INVALID_ARGS);
ASSERT_OK(zx::msi::create(msi, /*options=*/0, /*msi_id=*/0, vmo, /*vmo_offset=*/0, &int_0));
ASSERT_OK(msi.get_info(ZX_INFO_MSI, &msi_info, sizeof(msi_info), nullptr, nullptr));
ASSERT_EQ(msi_info.interrupt_count, 1);
// Bad handle (The interrupt handle is real, creeate takes fakes)
auto res = fake_object::fake_object_create();
ASSERT_OK(res.status_value());
ASSERT_STATUS(zx::msi::create(*zx::unowned_msi(res.value()), /*options=*/0, /*msi_id=*/0, vmo,
/*vmo_offset=*/0, &int_1),
ZX_ERR_WRONG_TYPE);
ASSERT_STATUS(zx::msi::create(msi, /*options=*/0, /*msi_id=*/0, vmo, /*vmo_offset=*/0, &int_1),
ZX_ERR_ALREADY_BOUND);
ASSERT_OK(zx::msi::create(msi, /*options=*/0, /*msi_id=*/1, vmo, /*vmo_offset=*/0, &int_1));
ASSERT_OK(msi.get_info(ZX_INFO_MSI, &msi_info, sizeof(msi_info), nullptr, nullptr));
ASSERT_EQ(msi_info.interrupt_count, 2);
int_0.reset();
int_1.reset();
ASSERT_OK(msi.get_info(ZX_INFO_MSI, &msi_info, sizeof(msi_info), nullptr, nullptr));
ASSERT_EQ(msi_info.interrupt_count, 0);
}
} // namespace