| // Copyright 2019 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-bti/bti.h> |
| #include <lib/fzl/pinned-vmo.h> |
| #include <lib/zx/vmo.h> |
| #include <zircon/rights.h> |
| |
| #include <utility> |
| |
| #include <zxtest/zxtest.h> |
| |
| namespace { |
| |
| constexpr size_t kVmoTestSize = 512 << 10; // 512KB |
| |
| class PinnedVmoTester : public zxtest::Test { |
| public: |
| void Init() { ASSERT_OK(zx::vmo::create(kVmoTestSize, 0, &vmo_)); } |
| |
| void InitContiguous() { |
| ASSERT_EQ(zx::vmo::create_contiguous(bti_, kVmoTestSize, 0, &vmo_), ZX_OK); |
| } |
| |
| void Pin(uint32_t rights) { |
| // Make sure our handles are valid: |
| EXPECT_TRUE(vmo_.is_valid()); |
| EXPECT_OK(pinned_vmo_.Pin(vmo_, bti_, rights)); |
| } |
| |
| // Check that the PinnedVmo is pinned; that it has regions |
| // and the regions are of non-zero size |
| void CheckPinned() const { |
| uint32_t region_count = pinned_vmo_.region_count(); |
| ASSERT_GT(region_count, 0); |
| for (uint32_t i = 0; i < region_count; ++i) { |
| fzl::PinnedVmo::Region r = pinned_vmo_.region(i); |
| EXPECT_GT(r.size, 0); |
| // We would check that phys_addr != 0, but fake-bti sets all the |
| // addresses to zero. |
| } |
| } |
| |
| // Check that the PinnedVmo is pinned; that it has only one region |
| // and the region is equivalent to the vmo size. |
| void CheckContiguousPinned() const { |
| ASSERT_EQ(pinned_vmo_.region_count(), 1); |
| fzl::PinnedVmo::Region r = pinned_vmo_.region(0); |
| EXPECT_EQ(r.size, kVmoTestSize); |
| CheckPinned(); |
| } |
| |
| void CheckUnpinned() const { ASSERT_EQ(pinned_vmo_.region_count(), 0); } |
| |
| void SetUp() override { ASSERT_OK(fake_bti_create(bti_.reset_and_get_address())); } |
| |
| ~PinnedVmoTester() override { pinned_vmo_.Unpin(); } |
| |
| zx::bti bti_; |
| zx::vmo vmo_; |
| fzl::PinnedVmo pinned_vmo_; |
| }; |
| |
| TEST_F(PinnedVmoTester, CreateAndPinTest) { |
| CheckUnpinned(); |
| Init(); |
| Pin(ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE); |
| CheckPinned(); |
| } |
| |
| TEST_F(PinnedVmoTester, CreateContiguousTest) { |
| CheckUnpinned(); |
| InitContiguous(); |
| Pin(ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE | ZX_BTI_CONTIGUOUS); |
| CheckContiguousPinned(); |
| } |
| |
| TEST_F(PinnedVmoTester, FailPinTwiceTest) { |
| Init(); |
| Pin(ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE); |
| EXPECT_EQ(pinned_vmo_.Pin(vmo_, bti_, ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE), ZX_ERR_BAD_STATE); |
| } |
| |
| TEST(PinnedVmoTests, FailPinArgsTest) { |
| fzl::PinnedVmo pinned_vmo; |
| zx::vmo vmo; |
| zx::bti bti; |
| EXPECT_EQ(pinned_vmo.Pin(vmo, bti, ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE), ZX_ERR_INVALID_ARGS); |
| ASSERT_OK(zx::vmo::create(kVmoTestSize, 0, &vmo)); |
| EXPECT_EQ(pinned_vmo.Pin(vmo, bti, ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE), ZX_ERR_INVALID_ARGS); |
| } |
| |
| TEST_F(PinnedVmoTester, PinRangeTest) { |
| CheckUnpinned(); |
| Init(); |
| EXPECT_OK(pinned_vmo_.PinRange(zx_system_get_page_size(), zx_system_get_page_size() * 4, vmo_, |
| *zx::unowned_bti(bti_), ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE)); |
| EXPECT_EQ(pinned_vmo_.region_count(), 4); |
| ASSERT_NO_FATAL_FAILURE(CheckPinned()); |
| } |
| |
| TEST_F(PinnedVmoTester, FailPinRangeTest) { |
| CheckUnpinned(); |
| Init(); |
| constexpr uint32_t options = ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE; |
| // offset not page aligned: |
| EXPECT_EQ(pinned_vmo_.PinRange(zx_system_get_page_size() + 1, zx_system_get_page_size(), vmo_, |
| *zx::unowned_bti(bti_), options), |
| ZX_ERR_INVALID_ARGS); |
| // length not page aligned: |
| EXPECT_EQ( |
| pinned_vmo_.PinRange(0, zx_system_get_page_size() + 1, vmo_, *zx::unowned_bti(bti_), options), |
| ZX_ERR_INVALID_ARGS); |
| // zero length: |
| EXPECT_EQ(pinned_vmo_.PinRange(0, 0, vmo_, *zx::unowned_bti(bti_), options), ZX_ERR_INVALID_ARGS); |
| } |
| |
| } // namespace |