[kernel][pmt] Optimize pinned contiguous memory
If a pmt dispatcher is pinning a contiguous vmo, then the array of
physical addresses only needs to contain a single element for the start
address.
ZX-4384 #done
Change-Id: Ia961dcaac2cbd2742ca2a5ecaec44697abe24eec
diff --git a/zircon/kernel/object/pinned_memory_token_dispatcher.cpp b/zircon/kernel/object/pinned_memory_token_dispatcher.cpp
index 7a2f2de..082c24d 100644
--- a/zircon/kernel/object/pinned_memory_token_dispatcher.cpp
+++ b/zircon/kernel/object/pinned_memory_token_dispatcher.cpp
@@ -32,11 +32,17 @@
LTRACE_ENTRY;
DEBUG_ASSERT(IS_PAGE_ALIGNED(pinned_vmo.offset()) && IS_PAGE_ALIGNED(pinned_vmo.size()));
- const size_t min_contig = bti->minimum_contiguity();
- DEBUG_ASSERT(fbl::is_pow2(min_contig));
+ size_t num_addrs;
+ if (!pinned_vmo.vmo()->is_contiguous()) {
+ const size_t min_contig = bti->minimum_contiguity();
+ DEBUG_ASSERT(fbl::is_pow2(min_contig));
+
+ num_addrs = ROUNDUP(pinned_vmo.size(), min_contig) / min_contig;
+ } else {
+ num_addrs = 1;
+ }
fbl::AllocChecker ac;
- const size_t num_addrs = ROUNDUP(pinned_vmo.size(), min_contig) / min_contig;
fbl::Array<dev_vaddr_t> addr_array(new (&ac) dev_vaddr_t[num_addrs], num_addrs);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
@@ -92,10 +98,8 @@
}
DEBUG_ASSERT(vaddr % min_contig == 0);
+ DEBUG_ASSERT(mapped_addrs_.size() == 1);
mapped_addrs_[0] = vaddr;
- for (size_t i = 1; i < mapped_addrs_.size(); ++i) {
- mapped_addrs_[i] = mapped_addrs_[i - 1] + min_contig;
- }
return ZX_OK;
}
@@ -250,7 +254,8 @@
if (num_pages != mapped_addrs_count) {
return ZX_ERR_INVALID_ARGS;
}
- const size_t min_contig = bti_->minimum_contiguity();
+ const size_t min_contig = pinned_vmo_.vmo()->is_contiguous()
+ ? pinned_vmo_.size() : bti_->minimum_contiguity();
size_t next_idx = 0;
for (size_t i = 0; i < found_addrs; ++i) {
dev_vaddr_t extent_base = pmo_addrs[i];
diff --git a/zircon/system/utest/core/BUILD.gn b/zircon/system/utest/core/BUILD.gn
index 4e4d2d0..1b73397 100644
--- a/zircon/system/utest/core/BUILD.gn
+++ b/zircon/system/utest/core/BUILD.gn
@@ -42,6 +42,7 @@
# These tests need get_root_resource(), which is only available in the
# unified core-tests binary.
unified_only = [
+ "bti",
"interrupt",
"profile",
"resource",
diff --git a/zircon/system/utest/core/bti/BUILD.gn b/zircon/system/utest/core/bti/BUILD.gn
new file mode 100644
index 0000000..6f94137
--- /dev/null
+++ b/zircon/system/utest/core/bti/BUILD.gn
@@ -0,0 +1,16 @@
+# 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.
+
+source_set("bti") {
+ testonly = true
+ sources = [
+ "bti.cpp",
+ ]
+ deps = [
+ "$zx/system/ulib/fdio",
+ "$zx/system/ulib/unittest",
+ "$zx/system/ulib/zircon",
+ "$zx/system/ulib/zx",
+ ]
+}
diff --git a/zircon/system/utest/core/bti/bti.cpp b/zircon/system/utest/core/bti/bti.cpp
new file mode 100644
index 0000000..a4cd006
--- /dev/null
+++ b/zircon/system/utest/core/bti/bti.cpp
@@ -0,0 +1,112 @@
+// 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/zx/bti.h>
+#include <lib/zx/iommu.h>
+#include <unittest/unittest.h>
+#include <zircon/syscalls/iommu.h>
+#include <zircon/types.h>
+
+extern "C" zx_handle_t get_root_resource(void);
+
+namespace {
+
+bool bti_create_test() {
+ BEGIN_TEST;
+
+ zx::iommu iommu;
+ zx::bti bti;
+ zx::pmt pmt;
+ // Please do not use get_root_resource() in new code. See ZX-1467.
+ zx::unowned_resource root_res(get_root_resource());
+ zx_iommu_desc_dummy_t desc;
+ // Please do not use get_root_resource() in new code. See ZX-1467.
+ ASSERT_EQ(zx_iommu_create(get_root_resource(), ZX_IOMMU_TYPE_DUMMY,
+ &desc, sizeof(desc), iommu.reset_and_get_address()), ZX_OK);
+ ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
+
+ END_TEST;
+}
+
+bool bti_pin_test_helper(bool contiguous_vmo) {
+ BEGIN_TEST;
+
+ zx::iommu iommu;
+ zx::bti bti;
+ // Please do not use get_root_resource() in new code. See ZX-1467.
+ zx::unowned_resource root_res(get_root_resource());
+ zx_iommu_desc_dummy_t desc;
+ // Please do not use get_root_resource() in new code. See ZX-1467.
+ ASSERT_EQ(zx_iommu_create(get_root_resource(), ZX_IOMMU_TYPE_DUMMY,
+ &desc, sizeof(desc), iommu.reset_and_get_address()), ZX_OK);
+ ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
+
+ static constexpr uint64_t kPageCount = 256;
+ static constexpr uint64_t kVmoSize = ZX_PAGE_SIZE * kPageCount;
+ zx::vmo vmo;
+ if (contiguous_vmo) {
+ ASSERT_EQ(zx::vmo::create_contiguous(bti, kVmoSize, 0, &vmo), ZX_OK);
+ } else {
+ ASSERT_EQ(zx::vmo::create(kVmoSize, 0, &vmo), ZX_OK);
+ }
+
+ zx_paddr_t paddrs[kPageCount];
+ zx::pmt pmt;
+ ASSERT_EQ(bti.pin(ZX_BTI_PERM_READ, vmo, 0, kVmoSize, paddrs, kPageCount, &pmt), ZX_OK);
+
+ ASSERT_EQ(pmt.unpin(), ZX_OK);
+
+ if (contiguous_vmo) {
+ for (unsigned i = 1; i < kPageCount; i++) {
+ ASSERT_EQ(paddrs[i], paddrs[0] + i * ZX_PAGE_SIZE);
+ }
+ }
+
+ END_TEST;
+}
+
+bool bti_pin_test() {
+ return bti_pin_test_helper(false);
+}
+
+bool bti_pin_contiguous_test() {
+ return bti_pin_test_helper(true);
+}
+
+bool bti_pin_contig_flag_test() {
+ BEGIN_TEST;
+
+ zx::iommu iommu;
+ zx::bti bti;
+ // Please do not use get_root_resource() in new code. See ZX-1467.
+ zx::unowned_resource root_res(get_root_resource());
+ zx_iommu_desc_dummy_t desc;
+ // Please do not use get_root_resource() in new code. See ZX-1467.
+ ASSERT_EQ(zx_iommu_create(get_root_resource(), ZX_IOMMU_TYPE_DUMMY,
+ &desc, sizeof(desc), iommu.reset_and_get_address()), ZX_OK);
+ ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
+
+ static constexpr uint64_t kPageCount = 256;
+ static constexpr uint64_t kVmoSize = ZX_PAGE_SIZE * kPageCount;
+ zx::vmo vmo;
+ ASSERT_EQ(zx::vmo::create_contiguous(bti, kVmoSize, 0, &vmo), ZX_OK);
+
+ zx_paddr_t paddr;
+ zx::pmt pmt;
+ ASSERT_EQ(bti.pin(ZX_BTI_PERM_READ | ZX_BTI_CONTIGUOUS, vmo, 0, kVmoSize, &paddr, 1, &pmt),
+ ZX_OK);
+
+ ASSERT_EQ(pmt.unpin(), ZX_OK);
+
+ END_TEST;
+}
+
+} // namespace
+
+BEGIN_TEST_CASE(bti_tests)
+RUN_TEST(bti_create_test);
+RUN_TEST(bti_pin_test);
+RUN_TEST(bti_pin_contiguous_test);
+RUN_TEST(bti_pin_contig_flag_test);
+END_TEST_CASE(bti_tests)